package com.brillilab.service.logic.method;

import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.common.IsDeleteEnum;
import com.brillilab.domain.enums.lab.LabMemberEnum;
import com.brillilab.domain.enums.method.MethodTypeLevelEnum;
import com.brillilab.domain.enums.method.MethodTypeVisibleEnum;
import com.brillilab.domain.po.lab.LabMember;
import com.brillilab.domain.po.method.Method;
import com.brillilab.domain.po.method.MethodLabView;
import com.brillilab.domain.po.method.MethodType;
import com.brillilab.domain.po.method.MethodTypeHide;
import com.brillilab.domain.po.topics.Topic;
import com.brillilab.domain.po.topics.TopicExperiment;
import com.brillilab.domain.po.topics.TopicTarget;
import com.brillilab.domain.vo.method.MethodTypePrefixEdit;
import com.brillilab.domain.vo.method.MethodTypeVo;
import com.brillilab.domain.vo.method.RecommendMethodTypeVo;
import com.brillilab.domain.vo.topics.NewMethodTypeVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.experiments.IExperimentService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.method.IMethodLabViewService;
import com.brillilab.service.core.method.IMethodService;
import com.brillilab.service.core.method.IMethodTypeHideService;
import com.brillilab.service.core.method.IMethodTypeService;
import com.brillilab.service.core.topics.ITopicExperimentService;
import com.brillilab.service.core.topics.ITopicService;
import com.brillilab.service.core.topics.ITopicTargetService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 方法类型业务逻辑
 * 方法类型，更新三级类型的名称时，
 * 须修改method_lab_view中未退出实验室的第三级类型名，
 * 退出的实验室重新加入时须修改method_lab_view表中的三级类型与用户当前类型一致
 *
 * @author wmh
 * @data 2019-02-25
 */
@Service
@Transactional
public class MethodTypeLogic {

    @Resource
    private IMethodTypeService methodTypeService;
    @Resource
    private IMethodLabViewService methodLabViewService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private IMethodService methodService;
    @Resource
    private IMethodTypeHideService methodTypeHideService;
    @Resource
    private ITopicService topicService;
    @Resource
    private IExperimentService experimentService;
    @Resource
    private ITopicTargetService topicTargetService;
    @Resource
    private ITopicExperimentService topicExperimentService;

    /**
     * 新增类型 (类型名称不能相同)
     * 二级类型和实验类型限制64字符
     *
     * @param add
     * @param userInfo
     * @return
     */
    public MethodTypeVo addNewMethodType(MethodTypeVo add, UserInfoVo userInfo) {
        Assert.isTrue(add != null && userInfo != null, "参数缺失！");
        Assert.isTrue(userInfo.getLabId() != null, "用户未加入实验室！");
        Assert.isTrue(!MethodTypeLevelEnum.LevelFirst.getLevel().equals(add.getLevel()), "一级类型无法添加！");
        Assert.isTrue(add.getName().length() < 100, "名称超长！");
//        Assert.isTrue(add.getName().matches(ValidatorUtil.SPECIFIC_SYMBOL_METHOD), "名称中不能有特殊符号！");

        //名称不能重复
        checkMethodNameRepeate(add, null, userInfo);

        //新增
        MethodType method = new MethodType();
        method.setName(add.getName().trim());
        method.setUserId(userInfo.getId());
        method.setLevel(add.getLevel());
        if (MethodTypeLevelEnum.LevelSecond.getLevel().equals(add.getLevel())) {
            List<MethodType> methodTypes = methodTypeService.selectListByLevelAndParentIdAndUserId(2, null, userInfo.getId());
            Assert.isTrue(methodTypes.size() < 500, "二级类型不能超过500条！");
            MethodType parent = methodTypeService.selectOneById(add.getParentId());
            //是否是本人的，系统的
            Assert.isTrue(parent != null && (parent.getUserId() == null || userInfo.getId().equals(parent.getUserId())), "父级类型不存在或已删除！");
            Assert.isTrue(MethodTypeLevelEnum.LevelFirst.getLevel().equals(parent.getLevel()), "父级类型不是一级类型！");
            method.setFirstId(parent.getId());
        } else if (MethodTypeLevelEnum.LevelThird.getLevel().equals(add.getLevel())) {
            List<MethodType> methodTypes = methodTypeService.selectListByLevelAndParentIdAndUserId(3, null, userInfo.getId());
            Assert.isTrue(methodTypes.size() < 1000, "三级类型不能超过1000条！");
            MethodType parent = methodTypeService.selectOneById(add.getParentId());
            //是否是本人的，系统的
            Assert.isTrue(parent != null && (parent.getUserId() == null || userInfo.getId().equals(parent.getUserId())), "父级类型不存在或已删除！");
            Assert.isTrue(MethodTypeLevelEnum.LevelSecond.getLevel().equals(parent.getLevel()), "父级类型不是二级类型！");
            method.setSecondId(parent.getId());
            method.setFirstId(parent.getFirstId());
        } else {
            throw new BrillilabException(ResultEnum.FAILURE, "方法类型Level不存在：" + add.getLevel());
        }

        methodTypeService.add(method);

        add.setId(method.getId());

        return add;
    }

    private void checkMethodNameRepeate(MethodTypeVo add, MethodType exist, UserInfoVo userInfo) {
        List<MethodType> levelList = methodTypeService.selectListByLevelAndParentIdAndUserId(add.getLevel(), add.getParentId(), userInfo.getId());
        List<String> names = levelList.stream().map(MethodType::getName).collect(Collectors.toList());
        if (exist != null) {
            names.remove(exist.getName());
        }
        Assert.isTrue(!names.contains(add.getName().trim()), "方法类型名称不能重复!");
    }


    /**
     * 三级类型前缀修改
     * @param edit
     * @param userInfo
     */
    public void editThirdMethodTypePrefix(MethodTypePrefixEdit edit,UserInfoVo userInfo) {
        String prefixNew=edit.getPrefix();
        Date date=new Date();
        Assert.isTrue(prefixNew.length() < 100, "名称超长！");
        List<Long> ids=edit.getIds().stream().filter(e -> !e.equals(-1L)).collect(Collectors.toList());
        List<MethodType> methodTypes=methodTypeService.listByIdList(ids);
        methodTypes.forEach(e -> Assert.isTrue(e.getUserId()!=null && e.getUserId().equals(userInfo.getId()), "您无法修改他人或公共方法类型!"));
        if(CollectionUtils.isNotEmpty(methodTypes)){
            Assert.notNull(methodTypes.get(0).getUserId(),"系统类型无法修改!");
            String prefixOld = methodTypes.get(0).getName().split(":")[0];
            List<String> myPrefixes = methodTypeService.selectAllThirdMethodPrefix(edit.getSecondTypeId(),userInfo.getId());
            List<String> canNotUse=myPrefixes.stream().filter(e -> e.equals(prefixOld)).collect(Collectors.toList());
            Assert.isTrue(!canNotUse.contains(prefixNew),"方法类型名称不能重复!");
            for (MethodType methodType:methodTypes){
                String newName = prefixNew + ":"+methodType.getName().split(":")[1];
                methodType.setName(newName);
                methodType.setUpdateTime(date);
            }
            methodTypeService.updateBatch(methodTypes);
        }
    }

    /**
     * 修改类型 (类型名称不能相同,更新三级类型的名称时，须修改method_lab_view中未退出实验室的第三级类型名)
     * 二级类型和实验类型限制64字符
     *
     * @param edit
     * @param userInfo
     * @return
     */
    public MethodTypeVo editMethodType(MethodTypeVo edit, UserInfoVo userInfo) {
        Assert.isTrue(edit != null && userInfo != null, "参数缺失！");
        Assert.isTrue(userInfo.getLabId() != null, "用户未加入实验室！");
        Assert.isTrue(!MethodTypeLevelEnum.LevelFirst.getLevel().equals(edit.getLevel()), "一级类型无法修改！");
        Assert.isTrue(edit.getName().length() < 100, "名称超长！");
//        Assert.isTrue(edit.getName().matches(ValidatorUtil.SPECIFIC_SYMBOL), "名称中不能有特殊符号！");

        MethodType methodType = methodTypeService.selectOneById(edit.getId());
        //是否是本人的，系统的
        Assert.isTrue(methodType != null && (methodType.getUserId().equals(userInfo.getId())
                || methodType.getUserId() == null), "类型不存在或已删除！");

        //名称不能重复
        checkMethodNameRepeate(edit, methodType, userInfo);

        //修改method_lab_view未退出实验室的第三级类型名
        if (MethodTypeLevelEnum.LevelThird.getLevel().equals(edit.getLevel())) {
            MethodLabView labView = methodLabViewService.selectOne(userInfo.getLabId(), userInfo.getId(), edit.getId());
            if (labView != null) {
                LabMember labMember = labMemberService.selectByIdAndState(labView.getLabMemberId(), LabMemberEnum.State.STATE_IN.getValue());
                if (labMember != null) {
                    labView.setThirdMethodTypeName(edit.getName());
                    methodLabViewService.updateById(labView);
                }
            }
        }
        //更新
        MethodType method = new MethodType();
        method.setId(edit.getId());
        method.setName(edit.getName());
        methodTypeService.updateById(method);

        return edit;
    }

    /**
     * 删除三级方法类型前缀
     * @param methodTypeIds
     * @param userInfo
     */
    public void deleteThirdMethodTypePrefix(List<Long> methodTypeIds,UserInfoVo userInfo) {
        methodTypeIds=methodTypeIds.stream().filter(e -> !e.equals(-1L)).collect(Collectors.toList());
        List<MethodType> methodTypes=methodTypeService.listByIdList(methodTypeIds);
        //系统类型无法删除
        methodTypes.forEach(e -> Assert.isTrue(e.getUserId()!=null && e.getUserId().equals(userInfo.getId()), "您无法修改他人或公共方法类型!"));
        //prefix类型下有方法无法删除
        int count = methodService.countCurrentListByMethodTypeIdsAndUserId(methodTypeIds,userInfo.getId(),false);
        Assert.isTrue(count==0,"该方法类型中存在方法，请先删除该方法！");
        if(CollectionUtils.isNotEmpty(methodTypeIds)){
            methodTypeService.deleteByMethodTypeIds(methodTypeIds,userInfo.getId());
        }
    }

    /**
     * 删除类型
     * 删除方法类型时需要判断该方法类型下面是否有方法：
     * 如果有方法，提示用户：该方法类型中存在方法，请先删除该方法！
     * 如果没有方法，提示用户：删除成功！删除失败，请重新尝试！
     *
     * @param typeId
     * @param userInfo
     * @return
     */
    public boolean deleteMethodType(Long typeId, UserInfoVo userInfo) {
        Assert.isTrue(typeId != null && userInfo != null, "参数缺失！");
        Assert.isTrue(userInfo.getLabId() != null, "用户未加入实验室！");
        MethodType methodType = methodTypeService.selectOneById(typeId);
        Assert.notNull(methodType, "类型ID不存在！");
        Assert.isTrue(!MethodTypeLevelEnum.LevelFirst.getLevel().equals(methodType.getLevel()), "一级类型无法删除！");
        Assert.isTrue(methodType.getUserId() != null, "系统类型无法删除！");
        Assert.isTrue(methodType.getUserId().equals(userInfo.getId()), "该方法类型不属于该用户！");
        //方法类型下是否有方法
        Assert.isTrue(!hasMethod(methodType, userInfo.getId()), "该方法类型中存在方法，请先删除该方法！");

        if (MethodTypeLevelEnum.LevelSecond.getLevel().equals(methodType.getLevel())) {
            //二级和三级删除
            List<MethodType> thirdTypes = methodTypeService.selectThirdListBySecondId(methodType.getId(), userInfo.getId());
            thirdTypes.add(methodType);
            thirdTypes.forEach(e -> {
                e.setIsDelete(IsDeleteEnum.YES.getValue());
            });
            return methodTypeService.updateBatch(thirdTypes);
        } else if (MethodTypeLevelEnum.LevelThird.getLevel().equals(methodType.getLevel())) {
            //三级标题删除
            methodType.setIsDelete(IsDeleteEnum.YES.getValue());
            return methodTypeService.updateById(methodType);
        } else {
            throw new BrillilabException(ResultEnum.FAILURE, "方法类型Level不存在：" + methodType.getLevel());
        }

    }

    public boolean hasMethod(MethodType methodType, Long userId) {
        if (MethodTypeLevelEnum.LevelFirst.getLevel().equals(methodType.getLevel())) {
            //二级
            List<MethodType> secondTypes = methodTypeService.selectSecondListByFirstId(methodType.getId(), userId);
            for (MethodType secondType : secondTypes) {
                //三级
                List<MethodType> thirdTypes = methodTypeService.selectThirdListBySecondId(secondType.getId(), userId);
                for (MethodType m : thirdTypes) {
                    //方法
                    List<Method> methods = methodService.selectListByMethodTypeId(m.getId(), userId);
                    if (CollectionUtils.isNotEmpty(methods)) {
                        return true;
                    }
                }
            }
        } else if (MethodTypeLevelEnum.LevelSecond.getLevel().equals(methodType.getLevel())) {
            //三级
            List<MethodType> thirdTypes = methodTypeService.selectThirdListBySecondId(methodType.getId(), userId);
            for (MethodType m : thirdTypes) {
                //方法
                List<Method> methods = methodService.selectListByMethodTypeId(m.getId(), userId);
                if (CollectionUtils.isNotEmpty(methods)) {
                    return true;
                }
            }
        } else if (MethodTypeLevelEnum.LevelThird.getLevel().equals(methodType.getLevel())) {
            //方法
            List<Method> methods = methodService.selectListByMethodTypeId(methodType.getId(), userId);
            return CollectionUtils.isNotEmpty(methods);
        }
        return false;
    }

    /**
     * 分级方法类型列表
     * TODO 如果有权限 如果没权限
     *
     * @param level
     * @param userInfo
     * @return
     */
    public List<MethodType> getMethodTypeList(Integer level, Long parentId, UserInfoVo userInfo) {
        Assert.isTrue(level != null && userInfo != null, "参数缺失！");
        Assert.isTrue(userInfo.getLabId() != null, "用户未加入实验室！");
        if (MethodTypeLevelEnum.LevelSecond.getLevel().equals(level)
                || MethodTypeLevelEnum.LevelThird.getLevel().equals(level)) {
            Assert.notNull(parentId, "二级类型与三级类型parentId不能为空！");
        }
        List<MethodType> rs=methodTypeService.selectListByLevelAndParentIdAndUserId(level,parentId,userInfo.getId());

        return appendMethodNumToMethodType(userInfo.getId(),rs);
    }


    /**
     * 批量隐藏三级类型Id
     * @param methodTypeIds
     * @param visible
     * @param userInfo
     */
    public void hideThirdMethodTypePrefix(List<Long> methodTypeIds,Integer visible,UserInfoVo userInfo) {
        methodTypeIds=methodTypeIds.stream().filter(e -> !e.equals(-1L)).collect(Collectors.toList());
        List<MethodType> methodTypes=methodTypeService.listByIdList(methodTypeIds);
        methodTypes.forEach(e -> Assert.isTrue( e.getUserId()==null ||(e.getUserId()!=null && e.getUserId().equals(userInfo.getId())), "您无法修改他人或公共方法类型!"));
        if(CollectionUtils.isNotEmpty(methodTypes)){
            if(BoolEnum.TRUE.getValue().equals(visible)){
                //可见
                methodTypeHideService.deleteByMethodTypeIds(methodTypeIds,userInfo.getId());
            }else if(BoolEnum.FALSE.getValue().equals(visible)){
                //数量
                List<MethodType> allBelowThird=methodTypeService.selectList(methodTypes.get(0).getSecondId(),MethodTypeLevelEnum.LevelThird.getLevel(),null,userInfo.getId(),true);
                List<MethodTypeHide> hides=methodTypeHideService.selectListByUserId(userInfo.getId());
                List<Long> allThirdIds=allBelowThird.stream().map(MethodType::getId).distinct().collect(Collectors.toList());
                List<MethodTypeHide> thirdHides=hides.stream().filter(e -> allThirdIds.contains(e.getMethodTypeId())).collect(Collectors.toList());
                //隐藏
                List<MethodTypeHide> methodTypeHides = methodTypeHideService.selectListByMethodTypeIds(methodTypeIds,userInfo.getId());
                List<Long> hideIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
                //老的保留，新的insert
                List<Long> newHideIds=methodTypeIds.stream().filter(e -> !hideIds.contains(e)).distinct().collect(Collectors.toList());
                //判断剩余量
                int leftNum = allBelowThird.size() - newHideIds.size() - thirdHides.size();
                Assert.isTrue(leftNum>0,"隐藏方法类型时,至少显示一个类型!");
                List<MethodTypeHide> newHides=newHideIds.stream().map(methodTypeId -> {
                    MethodTypeHide methodTypeHide=new MethodTypeHide();
                    methodTypeHide.setMethodTypeId(methodTypeId);
                    methodTypeHide.setUserId(userInfo.getId());
                    return methodTypeHide;
                }).collect(Collectors.toList());
                if(newHideIds.size()>0){
                    methodTypeHideService.insertBatch(newHides);
                }
            }
        }

    }

    /**
     * 方法类型隐藏
     * 隐藏方法类型时需要判断该方法类型下面是否有方法：
     * 如果没有方法，隐蔽
     *
     * @param id
     * @param hide
     * @param userInfo
     * @return
     */
    public boolean hideMethodType(Long id, Integer hide, UserInfoVo userInfo) {
        Assert.isTrue(id != null && hide != null && userInfo != null, "参数缺失！");
        Assert.isTrue(userInfo.getLabId() != null, "用户未加入实验室！");
        Assert.isTrue(hide.equals(MethodTypeVisibleEnum.HIDE.getValue())
                || hide.equals(MethodTypeVisibleEnum.VISIBLE.getValue()), "不存在的hide值：" + hide);
        MethodType methodType = methodTypeService.selectOneById(id);
        //是否是本人的，系统的
        Assert.isTrue(methodType != null && (userInfo.getId().equals(methodType.getUserId())
                || methodType.getUserId() == null), "类型不存在或已删除！");

        List<MethodType> allTypes=methodTypeService.selectList(userInfo.getId(),true);
        List<MethodTypeHide> myHides = methodTypeHideService.selectListByUserId(userInfo.getId());
        List<Long> hideTypeIds=myHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
        List<MethodType> hideTypes=methodTypeService.listByIdList(hideTypeIds);

        List<MethodTypeHide> adds = new ArrayList<>();
        List<Long> deletes = new ArrayList<>();
        if (MethodTypeLevelEnum.LevelFirst.getLevel().equals(methodType.getLevel())) {
            //将一级、二级和三级都隐藏/显示
            List<MethodType> firsts = allTypes.stream()
                    .filter(e -> MethodTypeLevelEnum.LevelFirst.getLevel().equals(e.getLevel()))
                    .collect(Collectors.toList());
            List<MethodType> seconds = allTypes.stream()
                    .filter(e -> MethodTypeLevelEnum.LevelSecond.getLevel().equals(e.getLevel()) && methodType.getId().equals(e.getFirstId()))
                    .collect(Collectors.toList());
            //判断是否可以隐藏
            assertCanHide(hide,hideTypes,firsts,MethodTypeLevelEnum.LevelFirst);
            //隐藏
            List<Long> secondIds = seconds.stream().map(MethodType::getId).collect(Collectors.toList());
            List<MethodType> thirdTypes = methodTypeService.selectThirdListBySecondIdList(secondIds, userInfo.getId());
            thirdTypes.add(methodType);
            thirdTypes.addAll(seconds);
            thirdTypes.forEach(e -> {
                setHideAndShowData(hide, userInfo, myHides, adds, deletes, e);
            });
        } else if (MethodTypeLevelEnum.LevelSecond.getLevel().equals(methodType.getLevel())) {
            List<MethodType> seconds = allTypes.stream()
                    .filter(e -> MethodTypeLevelEnum.LevelSecond.getLevel().equals(e.getLevel()) && methodType.getFirstId().equals(e.getFirstId()))
                    .collect(Collectors.toList());
            List<MethodType> thirdTypes = allTypes.stream()
                    .filter(e ->MethodTypeLevelEnum.LevelThird.getLevel().equals(e.getLevel()) && methodType.getId().equals(e.getSecondId()))
                    .collect(Collectors.toList());
            //判断是否可以隐藏
            assertCanHide(hide,hideTypes,seconds,MethodTypeLevelEnum.LevelSecond);
            //二级和三级都隐藏/显示
            thirdTypes.add(methodType);
            thirdTypes.forEach(e -> {
                setHideAndShowData(hide, userInfo, myHides, adds, deletes, e);
            });
        } else if (MethodTypeLevelEnum.LevelThird.getLevel().equals(methodType.getLevel())) {
            List<MethodType> thirds = allTypes.stream().filter(e -> MethodTypeLevelEnum.LevelThird.getLevel().equals(e.getLevel())).collect(Collectors.toList());
            //判断是否可以隐藏
            assertCanHide(hide,hideTypes,thirds,MethodTypeLevelEnum.LevelThird);
            //三级标题隐藏显示
            setHideAndShowData(hide, userInfo, myHides, adds, deletes, methodType);
        } else {
            throw new BrillilabException(ResultEnum.FAILURE, "方法类型Level不存在：" + methodType.getLevel());
        }

        //数据库操作
        if (deletes.size() > 0) {
            methodTypeHideService.deleteBatch(deletes);
        }
        if (adds.size() > 0) {
            methodTypeHideService.insertBatch(adds);
        }

        return true;
    }

    private void assertCanHide(Integer hide,List<MethodType> hideTypes,List<MethodType> levelTypes,MethodTypeLevelEnum level) {
        if(MethodTypeVisibleEnum.HIDE.getValue().equals(hide)){
            List<Long> secondHideTypeIds=hideTypes.stream()
                    .filter(e -> level.getLevel().equals(e.getLevel()))
                    .map(MethodType::getId).collect(Collectors.toList());
            long noHide=levelTypes.stream().filter(e -> !secondHideTypeIds.contains(e.getId())).count();
            Assert.isTrue(noHide>1,"隐藏方法类型时,至少显示一个类型!");
        }
    }

    private void setHideAndShowData(Integer hide, UserInfoVo userInfo, List<MethodTypeHide> myHides, List<MethodTypeHide> adds, List<Long> deletes, MethodType e) {
        if (hide.equals(MethodTypeVisibleEnum.HIDE.getValue())) {
            Long hideId = myHides.stream().filter(myHide -> myHide.getMethodTypeId().equals(e.getId())).map(MethodTypeHide::getId).findFirst().orElse(null);
            if (hideId != null) {
                return;
            }
            MethodTypeHide mh = new MethodTypeHide();
            mh.setMethodTypeId(e.getId());
            mh.setUserId(userInfo.getId());
            adds.add(mh);
        } else {
            Long hideId = myHides.stream().filter(myHide -> myHide.getMethodTypeId().equals(e.getId())).map(MethodTypeHide::getId).findFirst().orElse(null);
            if (hideId != null) {
                deletes.add(hideId);
            }
        }
    }

    /**
     * 方法类型推荐
     * <p>
     * 推荐类型规则：
     * 1）用户初次创建方法时系统默认推荐20个实验类型；
     * 2）选择推荐的实验类型后，类型选择区域自动显示出对应的一级类型、二级类型和实验类型，点击确定按钮后进入新建方法页面；
     * 3）用户使用过的推荐类型放到推荐类型最后，使用时间越近越靠后。
     *
     * @param userId
     * @return
     */
    public List<RecommendMethodTypeVo> recommendMethodType(Long userId) {
        Assert.notNull(userId, "参数缺失！");
        //实验室所有的三级类别
        List<RecommendMethodTypeVo> rs=methodTypeService.selectRecommendThirdMethodVo(userId);
        return appendMethodNumToRecommendMethodTypeVo(userId,rs);
    }

    /**
     * 所有方法类型
     * 用Map<String, List<MethodType>>存储
     *
     * @param userId
     * @return
     */
    public List<NewMethodTypeVo> getAllMethodTypeMap(Long userId) {
        List<MethodTypeHide> methodTypeHides=methodTypeHideService.selectListByUserId(userId);
        List<Long> hideMethodTypeIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());

        List<MethodType> firstTypes = methodTypeService
                .selectListByLevelAndParentIdAndUserId(
                        MethodTypeLevelEnum.LevelFirst.getLevel(), null, userId);
        List<MethodType> secondTypes = methodTypeService
                .selectListByLevelAndParentIdAndUserId(
                        MethodTypeLevelEnum.LevelSecond.getLevel(), null, userId);
        List<MethodType> thirdTypes = methodTypeService
                .selectListByLevelAndParentIdAndUserId(
                        MethodTypeLevelEnum.LevelThird.getLevel(), null, userId);
        List<Method> methods=methodService.getMethodListByUserIdAndState(userId,BoolEnum.FALSE,BoolEnum.TRUE,true);

        return getGroupedMethodTypeList(firstTypes,secondTypes,thirdTypes,methods,null,hideMethodTypeIds,false);
    }

    /**
     * 所有方法类型
     * 用Map<String, List<MethodType>>存储
     *
     * @param userId
     * @return
     */
    public List<NewMethodTypeVo> getAllVisibleMethodTypeMap(Long userId) {
        List<MethodType> methodTypes = methodTypeService.selectList(userId,false);
        List<MethodTypeHide> methodTypeHides=methodTypeHideService.selectListByUserId(userId);
        List<Long> hideMethodTypeIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
        methodTypes=methodTypes.stream().filter(e -> !hideMethodTypeIds.contains(e.getId())).collect(Collectors.toList());

        List<MethodType> firstTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel())).collect(Collectors.toList());
        List<MethodType> secondTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())).collect(Collectors.toList());
        List<MethodType> thirdTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).collect(Collectors.toList());

        List<Method> methods=methodService.getMethodListByUserIdAndState(userId,BoolEnum.FALSE,BoolEnum.TRUE,true).stream()
                .filter(e -> !hideMethodTypeIds.contains(e.getMethodTypeId()) && e.getCurrent().equals(1)).collect(Collectors.toList());

        return getGroupedMethodTypeList(firstTypes,secondTypes,thirdTypes,methods,null,null,false);
    }

    /**
     * 参考方法类型列表
     * @return
     */
    public List<MethodType> getReferenceMethodType() {
        List<MethodType> rs=methodTypeService.selectReferenceMethodType();
        return appendMethodNumToMethodType(null,rs);
    }

    /**
     * 分享方法接收，方法类型的处理
     *
     * @param methodId
     * @param labId
     * @param userId
     * @return
     */
    public void setVisibleForMethodType(Long methodId, Long labId, Long userId) {
        Assert.isTrue(methodId != null && labId != null && userId != null, "参数缺失！");

        Method oriMethod = methodService.getById(methodId);
        Assert.isTrue(oriMethod != null && oriMethod.getIsDelete().equals(IsDeleteEnum.NO.getValue()), "初始方法不存在！");
        showMethodType(oriMethod.getMethodTypeId(), userId);
    }

    public void showMethodType(Long thirdMethodTypeId, Long userId) {
        List<Long> delete = new ArrayList<>();

        //来源方法的类型
        MethodType oriThirdMethodType = methodTypeService.selectOneById(thirdMethodTypeId);
        Assert.isTrue(oriThirdMethodType != null && oriThirdMethodType.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel()), "数据异常！");

        MethodType oriSecondMethodType = methodTypeService.selectOneById(oriThirdMethodType.getSecondId());
        Assert.isTrue(oriSecondMethodType != null && oriSecondMethodType.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel()), "数据异常！");

        MethodType mySecondMethodType = methodTypeService.selectSecondType(oriSecondMethodType.getName(), oriSecondMethodType.getFirstId(), userId);
        Assert.isTrue(mySecondMethodType != null && mySecondMethodType.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel()), "二级方法类型不存在！");

        MethodType myThirdMethodType = methodTypeService.selectThirdType(oriThirdMethodType.getName(), mySecondMethodType.getId(), userId);
        Assert.isTrue(myThirdMethodType != null && myThirdMethodType.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel()), "三级方法类型不存在！");

        MethodType firstMethodType = methodTypeService.selectOneById(oriThirdMethodType.getFirstId());
        Assert.isTrue(firstMethodType != null && firstMethodType.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel()), "一级方法类型不存在！");

        //如果一级类型隐藏，取消隐藏
        List<MethodTypeHide> methodTypeHides = methodTypeHideService.selectListByUserId(userId);
        final Long firstTypeId = firstMethodType.getId();
        methodTypeHides.stream().filter(e -> e.getMethodTypeId().equals(firstTypeId)).findFirst().ifPresent(firstHide -> delete.add(firstHide.getId()));

        //如果二级类型隐藏，取消隐藏
        final Long secondTypeId = mySecondMethodType.getId();
        methodTypeHides.stream().filter(e -> e.getMethodTypeId().equals(secondTypeId)).findFirst().ifPresent(secondHide -> delete.add(secondHide.getId()));

        //如果三级类型隐藏，取消隐藏
        final Long thirdTypeId = myThirdMethodType.getId();
        methodTypeHides.stream().filter(e -> e.getMethodTypeId().equals(thirdTypeId)).findFirst().ifPresent(thirdHide -> delete.add(thirdHide.getId()));

        if (CollectionUtils.isNotEmpty(delete)) {
            methodTypeHideService.deleteBatch(delete);
        }
    }

    public List<MethodType> appendMethodNumToMethodType(Long userId,List<MethodType> methodTypes){
        List<Long> thirdMethodTypeIds=methodTypes.stream()
                .filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel()))
                .map(MethodType::getId).distinct().collect(Collectors.toList());

        List<Method> methods = methodService.selectCurrentListByMethodTypeIdsAndUserId(thirdMethodTypeIds,userId,true);
        methodTypes.forEach(type -> {
            List<Method> thisMethods=methods.stream().filter(method -> method.getMethodTypeId().equals(type.getId())).collect(Collectors.toList());
            type.setMethodNum(thisMethods.size());
        });
        return methodTypes;
    }

    public List<RecommendMethodTypeVo> appendMethodNumToRecommendMethodTypeVo(Long userId,List<RecommendMethodTypeVo> methodTypes){
        List<Long> thirdMethodTypeIds=methodTypes.stream()
                .map(RecommendMethodTypeVo::getId).distinct().collect(Collectors.toList());

        List<Method> methods = methodService.selectCurrentListByMethodTypeIdsAndUserId(thirdMethodTypeIds,userId,true);
        methodTypes.forEach(type -> {
            List<Method> thisMethods=methods.stream().filter(method -> method.getMethodTypeId().equals(type.getId())).collect(Collectors.toList());
            type.setMethodNum(thisMethods.size());
        });
        return methodTypes;
    }

    /**
     * 搜索
     * @param level
     * @param name
     * @param userId
     * @return
     */
    public List<MethodType> search(Long parentId,Integer level,String name,Long userId) {
        List<MethodType> methodTypes =  methodTypeService.selectList(parentId,level,name,userId,false);
        return appendMethodNumToMethodType(userId,methodTypes);
    }

    /**
     * 新建实验-常用方法类型
     * @param topicTargetId
     * @param userInfo
     * @return
     */
    public List<NewMethodTypeVo> getTopicFreqMethodTypeList(Long topicTargetId,UserInfoVo userInfo) {
        TopicTarget topicTarget=topicTargetService.selectById(topicTargetId);
        Assert.notNull(topicTarget,"课题目标不存在!");
        Topic topic=topicService.selectById(topicTarget.getTopicId());
        Assert.notNull(topic,"课题不存在!");
        LabMember labMember=labMemberService.selectById(topic.getExecutorId());
        Assert.notNull(labMember,"课题主执行人不存在!");
        List<TopicExperiment> experiments=topicExperimentService.getTopicExperimentList(topicTargetId);
        List<Long> usedMethodTypeId=experiments.stream().filter(e -> BoolEnum.FALSE.getValue().equals(e.getIsDelete())).map(TopicExperiment::getMethodTypeId).distinct().collect(Collectors.toList());

        List<MethodType> freqTypes = methodTypeService.selectFreqUseThirdMethod(userInfo.getId());
        List<Long> firstIds=freqTypes.stream().map(MethodType::getFirstId).distinct().collect(Collectors.toList());
        List<Long> secondIds=freqTypes.stream().map(MethodType::getSecondId).distinct().collect(Collectors.toList());
        List<MethodType> firstTypes=methodTypeService.listByIdList(firstIds);
        List<MethodType> secondTypes=methodTypeService.listByIdList(secondIds);
        List<MethodType> thirdTypes=freqTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).collect(Collectors.toList());

        List<Long> thirdIds=thirdTypes.stream().map(MethodType::getId).distinct().collect(Collectors.toList());
        List<Method> methods=methodService.selectCurrentListByMethodTypeIdsAndUserId(thirdIds,labMember.getUserId(),true);

        return getGroupedMethodTypeList(firstTypes,secondTypes,thirdTypes,methods,usedMethodTypeId,null,true);
    }

    /**
     * 新建实验-最常用方法类型
     * @param topicTargetId
     * @param userInfo
     * @return
     */
    public List<NewMethodTypeVo> getTopTopicFreqMethodTypeList(Long topicTargetId,UserInfoVo userInfo) {
        TopicTarget topicTarget=topicTargetService.selectById(topicTargetId);
        Assert.notNull(topicTarget,"课题目标不存在!");
        Topic topic=topicService.selectById(topicTarget.getTopicId());
        Assert.notNull(topic,"课题不存在!");
        LabMember labMember=labMemberService.selectById(topic.getExecutorId());
        Assert.notNull(labMember,"课题主执行人不存在!");
        List<TopicExperiment> experiments=topicExperimentService.getTopicExperimentList(topicTargetId);
        List<Long> usedMethodTypeId=experiments.stream().filter(e -> BoolEnum.FALSE.getValue().equals(e.getIsDelete())).map(TopicExperiment::getMethodTypeId).distinct().collect(Collectors.toList());

        List<MethodType> freqTypes = methodTypeService.selectTopFreqUseThirdMethod(userInfo.getId());
        List<MethodType> thirdTypes=freqTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).collect(Collectors.toList());

        List<Long> thirdIds=thirdTypes.stream().map(MethodType::getId).distinct().collect(Collectors.toList());
        List<Method> methods=methodService.selectCurrentListByMethodTypeIdsAndUserId(thirdIds,labMember.getUserId(),true);

        return getMethodTypeVoList(thirdTypes,methods,usedMethodTypeId);
    }

    /**
     * 获取NewMethodTypeVo
     * @param types
     * @param methods
     * @param usedMethodTypeId
     * @return
     */
    private List<NewMethodTypeVo> getMethodTypeVoList(List<MethodType> types, List<Method> methods, List<Long> usedMethodTypeId) {
        List<NewMethodTypeVo> thirdList;
        // 常用列表逻辑
        thirdList = types.stream().map(e ->{
            String name = e.getName();
            String prefix = name.contains(":")?name.split(":")[0]:name;
            name = name.contains(":")?name.split(":")[1]:name;
            NewMethodTypeVo last=new NewMethodTypeVo();
            List<Method> thisMethods=methods.stream().filter(m -> m.getMethodTypeId().equals(e.getId())).collect(Collectors.toList());
            last.setBelowType(null);
            last.setId(e.getId());
            last.setFirstTypeId(e.getFirstId());
            last.setSecondTypeId(e.getSecondId());
            last.setLevel(e.getLevel());
            last.setName(name);
            last.setMethodNum(CollectionUtils.isNotEmpty(thisMethods)?thisMethods.size():0);
            last.setPrefix(prefix);
            last.setSecondSort(e.getSecondSort());
            if(usedMethodTypeId!=null){
                last.setHasUsed(usedMethodTypeId.contains(e.getId()));
            }
            last.setIsSystem(e.getUserId()==null);
            return last;
        }).collect(Collectors.toList());

        return thirdList;
    }

    /**
     * 新建课题-方法类型列表
     * @param topicTargetId
     * @param userInfo
     * @return
     */
    public List<NewMethodTypeVo> getTopicMethodTypeList(Long topicTargetId,UserInfoVo userInfo) {

        TopicTarget topicTarget=topicTargetService.selectById(topicTargetId);
        Assert.notNull(topicTarget,"课题目标不存在!");
        Topic topic=topicService.selectById(topicTarget.getTopicId());
        Assert.notNull(topic,"课题不存在!");
        LabMember labMember=labMemberService.selectById(topic.getExecutorId());
        Assert.notNull(labMember,"课题主执行人不存在!");
        List<TopicExperiment> experiments=topicExperimentService.getTopicExperimentList(topicTargetId);
        List<Long> usedMethodTypeId=experiments.stream().filter(e -> BoolEnum.FALSE.getValue().equals(e.getIsDelete())).map(TopicExperiment::getMethodTypeId).distinct().collect(Collectors.toList());

        List<MethodType> methodTypes = methodTypeService.selectList(labMember.getUserId(),false);
        List<MethodTypeHide> methodTypeHides=methodTypeHideService.selectListByUserId(labMember.getUserId());
        List<Long> hideMethodTypeIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
        methodTypes=methodTypes.stream().filter(e -> !hideMethodTypeIds.contains(e.getId())).collect(Collectors.toList());

        List<MethodType> firstTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelFirst.getLevel())).collect(Collectors.toList());
        List<MethodType> secondTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelSecond.getLevel())).collect(Collectors.toList());
        List<MethodType> thirdTypes=methodTypes.stream().filter(e -> e.getLevel().equals(MethodTypeLevelEnum.LevelThird.getLevel())).collect(Collectors.toList());

        List<Method> methods=methodService.getMethodListByUserIdAndState(labMember.getUserId(),BoolEnum.FALSE,BoolEnum.TRUE,true).stream()
                .filter(e -> !hideMethodTypeIds.contains(e.getMethodTypeId())).collect(Collectors.toList());

        return getGroupedMethodTypeList(firstTypes,secondTypes,thirdTypes,methods,usedMethodTypeId,null,false);
    }

    private Map<String, List<MethodType>> getThirdTypeTitleMap(List<MethodType> thirdTypes) {
        List<String> titles=thirdTypes.stream().map(e -> e.getName().split(":")[0]).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String, List<MethodType>> titleTypeMap=new HashMap<>();
        titles.forEach(title -> {
            List<MethodType> thisTitle=thirdTypes.stream().filter(e -> e.getName().split(":")[0].equals(title)).collect(Collectors.toList());
            titleTypeMap.put(title,thisTitle);
        });
        return titleTypeMap;
    }

    private List<NewMethodTypeVo> getGroupedMethodTypeList(List<MethodType> firstTypes,List<MethodType> secondTypes,List<MethodType> thirdTypes,List<Method> methods,List<Long> usedMethodTypeId,List<Long> hideMethodTypeIds,boolean isFreq) {
        //一级
        return firstTypes.stream().map(firstType -> {
            NewMethodTypeVo first=new NewMethodTypeVo();
            //二级
            List<NewMethodTypeVo> secondList=secondTypes.stream().filter(e -> e.getFirstId().equals(firstType.getId())).map(secondType -> {
                NewMethodTypeVo second=new NewMethodTypeVo();
                List<MethodType> thisThird=thirdTypes.stream().filter(e -> e.getSecondId().equals(secondType.getId())).collect(Collectors.toList());
                Map<String, List<MethodType>> titleTypeMap=getThirdTypeTitleMap(thisThird);
                //title
                List<NewMethodTypeVo> thirdList;
                if(!isFreq){
                    //所有列表逻辑
                    thirdList=titleTypeMap.keySet().stream().map(title -> {
                        NewMethodTypeVo third=new NewMethodTypeVo();
                        List<NewMethodTypeVo> lastList = new ArrayList<>();
                        if(titleTypeMap.get(title)!=null){
                            MethodType oneType=titleTypeMap.get(title).get(0);
                            //三级
                            lastList = titleTypeMap.get(title).stream().map(thirdType -> {
                                NewMethodTypeVo last=new NewMethodTypeVo();
                                List<Method> thisMethods=methods.stream().filter(e -> e.getMethodTypeId().equals(thirdType.getId())).collect(Collectors.toList());
                                last.setBelowType(null);
                                last.setId(thirdType.getId());
                                last.setFirstTypeId(thirdType.getFirstId());
                                last.setSecondTypeId(thirdType.getSecondId());
                                last.setLevel(thirdType.getLevel());
                                last.setName(thirdType.getName().contains(":")?thirdType.getName().split(":")[1]:thirdType.getName());
                                last.setMethodNum(CollectionUtils.isNotEmpty(thisMethods)?thisMethods.size():0);
                                last.setPrefix(title);
                                last.setSecondSort(thirdType.getSecondSort());
                                if(usedMethodTypeId!=null){
                                    last.setHasUsed(usedMethodTypeId.contains(thirdType.getId()));
                                }
                                last.setIsSystem(thirdType.getUserId()==null);
                                if(hideMethodTypeIds!=null){
                                    last.setVisible(!hideMethodTypeIds.contains(last.getId()));
                                }
                                return last;
                            }).sorted((e1,e2) -> {
                                Integer sort1=e1.getSecondSort();
                                Integer sort2=e2.getSecondSort();
                                if(sort1==null && sort2 ==null){
                                    return 0;
                                }
                                if(sort1==null && sort2!=null){
                                    return -1;
                                }
                                if(sort1!=null && sort2==null){
                                    return 1;
                                }
                                if(sort1!=null && sort2!=null && sort1>sort2){
                                    return 1;
                                }
                                if(sort1!=null && sort2!=null && sort1<sort2){
                                    return -1;
                                }
                                return 0;
                            }).collect(Collectors.toList());
                            third.setBelowType(lastList);
                            third.setName(title);
                            third.setFirstTypeId(secondType.getFirstId());
                            third.setSecondTypeId(secondType.getId());
                            third.setFirstSort(oneType.getFirstSort());
                            third.setIsSystem(oneType.getUserId()==null);
                            third.setLevel(MethodTypeLevelEnum.PREFIX.getLevel());
                            if(hideMethodTypeIds!=null){
                                List<Long> allIds=titleTypeMap.get(title).stream().map(MethodType::getId).distinct().collect(Collectors.toList());
                                allIds.removeAll(hideMethodTypeIds);
                                third.setVisible(!CollectionUtils.isEmpty(allIds));
                            }
                            return third;
                        }
                        return null;
                    }).filter(Objects::nonNull).sorted((e1,e2) -> {
                        Integer sort1=e1.getFirstSort();
                        Integer sort2=e2.getFirstSort();
                        if(sort1==null && sort2 ==null){
                            return 0;
                        }
                        if(sort1==null && sort2!=null){
                            return 1;
                        }
                        if(sort1!=null && sort2==null){
                            return -1;
                        }
                        if(sort1!=null && sort2!=null && sort1>sort2){
                            return 1;
                        }
                        if(sort1!=null && sort2!=null && sort1<sort2){
                            return -1;
                        }
                        return 0;
                    }).collect(Collectors.toList());
                }else {
                    // 常用列表逻辑
                    thirdList = thisThird.stream().map(e ->{
                        String name = e.getName();
                        String prefix = name.contains(":")?name.split(":")[0]:name;
                        name = name.contains(":")?name.split(":")[1]:name;
                        NewMethodTypeVo last=new NewMethodTypeVo();
                        List<Method> thisMethods=methods.stream().filter(m -> m.getMethodTypeId().equals(e.getId())).collect(Collectors.toList());
                        last.setBelowType(null);
                        last.setId(e.getId());
                        last.setFirstTypeId(e.getFirstId());
                        last.setSecondTypeId(e.getSecondId());
                        last.setLevel(e.getLevel());
                        last.setName(name);
                        last.setMethodNum(CollectionUtils.isNotEmpty(thisMethods)?thisMethods.size():0);
                        last.setPrefix(prefix);
                        last.setSecondSort(e.getSecondSort());
                        if(usedMethodTypeId!=null){
                            last.setHasUsed(usedMethodTypeId.contains(e.getId()));
                        }
                        last.setIsSystem(e.getUserId()==null);
                        if(hideMethodTypeIds!=null){
                            last.setVisible(!hideMethodTypeIds.contains(last.getId()));
                        }
                        return last;
                    }).collect(Collectors.toList());
                }
                second.setBelowType(thirdList);
                second.setId(secondType.getId());
                second.setFirstTypeId(secondType.getFirstId());
                second.setSecondTypeId(secondType.getSecondId());
                second.setLevel(secondType.getLevel());
                second.setName(secondType.getName());
                second.setIsSystem(secondType.getUserId()==null);
                if(hideMethodTypeIds!=null){
                    second.setVisible(!hideMethodTypeIds.contains(second.getId()));
                }
                return second;
            }).collect(Collectors.toList());
            //重排序
            List<NewMethodTypeVo> newSecondList=new ArrayList<>();
            secondList.stream().filter(e ->e.getName().equals("细胞")).findFirst().ifPresent(newSecondList::add);
            secondList.stream().filter(e ->e.getName().equals("蛋白质")).findFirst().ifPresent(newSecondList::add);
            secondList.stream().filter(e ->e.getName().equals("核酸")).findFirst().ifPresent(newSecondList::add);
            List<NewMethodTypeVo> lefted=secondList.stream().filter(e -> !e.getName().equals("细胞") && !e.getName().equals("蛋白质") && !e.getName().equals("核酸")).collect(Collectors.toList());
            newSecondList.addAll(lefted);
            first.setBelowType(newSecondList);
            first.setId(firstType.getId());
            first.setFirstTypeId(firstType.getFirstId());
            first.setSecondTypeId(firstType.getSecondId());
            first.setLevel(firstType.getLevel());
            first.setName(firstType.getName());
            first.setIsSystem(firstType.getUserId()==null);
            if(hideMethodTypeIds!=null){
                first.setVisible(!hideMethodTypeIds.contains(first.getId()));
            }
            return first;
        }).sorted((e1,e2) -> {
            int compare=Long.compare(e1.getId(),e2.getId());
            if(compare == -1) return 1;
            if(compare == 1) return -1;
            else return compare;
        } ).collect(Collectors.toList());
    }

    /**
     * 搜索
     * @param name
     * @param topicTargetId
     * @return
     */
    public List<NewMethodTypeVo> search(String name,Long topicTargetId) {
        TopicTarget topicTarget=topicTargetService.selectById(topicTargetId);
        Assert.notNull(topicTarget,"课题目标不存在!");
        Topic topic=topicService.selectById(topicTarget.getTopicId());
        Assert.notNull(topic,"课题不存在!");
        LabMember labMember=labMemberService.selectById(topic.getExecutorId());
        Assert.notNull(labMember,"课题主执行人不存在!");
        List<TopicExperiment> experiments=topicExperimentService.getTopicExperimentList(topicTargetId);
        List<Long> usedMethodTypeId=experiments.stream().filter(e -> BoolEnum.FALSE.getValue().equals(e.getIsDelete())).map(TopicExperiment::getMethodTypeId).distinct().collect(Collectors.toList());

        Long executorId = labMember.getUserId();
        List<MethodType> methodTypes = methodTypeService.selectList(null,MethodTypeLevelEnum.LevelThird.getLevel(),name,executorId,false);
        List<MethodTypeHide> methodTypeHides=methodTypeHideService.selectListByUserId(executorId);
        List<Long> hideMethodTypeIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
        methodTypes=methodTypes.stream().filter(e -> !hideMethodTypeIds.contains(e.getId())).collect(Collectors.toList());
        List<Method> methods=methodService.getMethodListByUserIdAndState(executorId,BoolEnum.FALSE,BoolEnum.TRUE,true);

        Map<String, List<MethodType>> titleTypeMap=getThirdTypeTitleMap(methodTypes);
        //title
        List<NewMethodTypeVo> thirdList=new ArrayList<>();
        titleTypeMap.keySet().forEach(title -> {
            List<NewMethodTypeVo> lastList = new ArrayList<>();
            if(titleTypeMap.get(title)!=null){
                //三级
                lastList = titleTypeMap.get(title).stream().map(thirdType -> {
                    NewMethodTypeVo last=new NewMethodTypeVo();
                    List<Method> thisMethods=methods.stream().filter(e -> e.getMethodTypeId().equals(thirdType.getId())).collect(Collectors.toList());
                    last.setBelowType(null);
                    last.setId(thirdType.getId());
                    last.setFirstTypeId(thirdType.getFirstId());
                    last.setSecondTypeId(thirdType.getSecondId());
                    last.setLevel(thirdType.getLevel());
                    last.setName(thirdType.getName().contains(":")?thirdType.getName().split(":")[1]:thirdType.getName());
                    last.setMethodNum(CollectionUtils.isNotEmpty(thisMethods)?thisMethods.size():0);
                    last.setPrefix(title);
                    last.setHasUsed(usedMethodTypeId.contains(thirdType.getId()));
                    return last;
                }).collect(Collectors.toList());
                thirdList.addAll(lastList);
            }
        });
        return thirdList;
    }
}
